package cn.jingyuan.swan.uaa.web.config;

import cn.jingyuan.swan.cloud.oauth2.DefaultOAuth2ResourceDetails;
import cn.jingyuan.swan.cloud.oauth2.client.DefaultOAuth2ClientProperties;
import cn.jingyuan.swan.cloud.oauth2.error.DefaultOAuth2AccessDeniedHandler;
import cn.jingyuan.swan.cloud.oauth2.error.DefaultOAuth2AuthenticationEntryPoint;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.authentication.TokenExtractor;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.web.authentication.logout.CookieClearingLogoutHandler;
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler;

import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;


/**
 * 资源服务器配置
 */
@Slf4j
@Configuration
@EnableResourceServer
@EnableConfigurationProperties({DefaultOAuth2ResourceDetails.class, DefaultOAuth2ClientProperties.class})
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

    @Resource
    TokenStore tokenStore;

    @Resource
    TokenExtractor tokenExtractor;

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources
            .accessDeniedHandler(new DefaultOAuth2AccessDeniedHandler())
            .authenticationEntryPoint(new DefaultOAuth2AuthenticationEntryPoint());
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .cors().disable();

        http.httpBasic();

        http.sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);

        http.formLogin()
            .loginPage("/login").permitAll();

        http.logout()
            .permitAll()

            // logout 退出清除 cookie
            .addLogoutHandler(new CookieClearingLogoutHandler("token", "remember-me"))
            .logoutSuccessHandler(new LogoutSuccessHandler());

        http.exceptionHandling()
            .accessDeniedHandler(new DefaultOAuth2AccessDeniedHandler())
            .authenticationEntryPoint(new DefaultOAuth2AuthenticationEntryPoint());


        http.requestMatchers()
            .antMatchers("/**");

        http.authorizeRequests()
            .anyRequest().permitAll();
    }


    public class LogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler {

        public LogoutSuccessHandler() {
            // 重定向到原地址
            this.setUseReferer(true);
        }

        @Override
        public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
            throws IOException, ServletException {
            try {
                // 解密请求头
                authentication = tokenExtractor.extract(request);
                if (null != authentication && null != authentication.getPrincipal()) {
                    String tokenValue = authentication.getPrincipal().toString();
                    log.debug("revokeToken tokenValue:{}", tokenValue);
                    // 移除 token
                    tokenStore.removeAccessToken(tokenStore.readAccessToken(tokenValue));
                }
            } catch (Exception e) {
                log.error("revokeToken error:{}", e);
            }
            super.onLogoutSuccess(request, response, authentication);
        }
    }

}
